package com.cloud.service;


import cn.hutool.core.util.IdUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class PaymentService {
    /**
     * 服务降级1-指定回滚处理方法：
     * 声明一个失败回滚处理函数 exceptionFallBack，当执行超时（默认是 1000毫秒），就会执行 fallback 函数，返回错误提示。
     * id为耦数时 正常访问，当id为奇数时 执行回滚处理方法。
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "exceptionFallBack")
    public String paymentOKOrFallback(Integer id) {
        if (id % 2 == 0) {
            return "请求成功！线程池:" + Thread.currentThread().getName() + " PaymentService paymentOK, id:" + id ;
        } else {
            throw new RuntimeException("运行时异常！");
        }
    }
    /**
     * 降级方法，做用：当原方法出现问题时，用此方法代替。
     * @param id 参数必须和原方法参数一直
     * @return 与原方法的返回值一直
     */
    public String exceptionFallBack(Integer id) {
        return "服务降级！线程池:"+Thread.currentThread().getName() + "\t" + "执行超时 或 id为奇数时执行,id: " + id;
    }

    /**
     * 服务降级2-设置服务超时时长(超时访问)，设置自身调用超时的峰值，峰值内正常运行，超过了峰值需要服务降级 自动调用 fallbackMethod 指定的方法
     * 超时异常或者运行异常 都会进行服务降级
     * @param timeout 超过设置的超时峰值 3秒 则服务降级 自动调用 fallbackMethod
     * @return
     */
    @HystrixCommand(fallbackMethod = "timeOutFallBack", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
    })
    public String paymentTimeOut(Long timeout) {
        long start = System.currentTimeMillis();
        try {
            TimeUnit.SECONDS.sleep(timeout);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        return "请求成功！线程池:  " + Thread.currentThread().getName() + " paymentTimeOut,timeout:  " + timeout +"  耗时(豪秒): " + (end - start);
    }

    /**
     * paymentTimeOut 方法失败后 自动调用此方法 实现服务降级 告知调用者 paymentTimeOut 目前无法正常调用
     * @param timeout
     * @return
     */
    public String timeOutFallBack(Long timeout) {
        return "超时访问-服务降级！线程池:" + Thread.currentThread().getName() + "系统繁忙或者运行报错，请稍后再试,峰值timeout:  " + timeout;
    }

//    /**
//     * 服务熔断 超时、异常、都会触发熔断
//     * 1、默认是最近10秒内收到不小于10个请求，<br/>
//     * 2、并且有60%是失败的<br/>
//     * 3、就开启断路器<br/>
//     * 4、开启后所有请求不再转发，降级逻辑自动切换为主逻辑，减小调用方的响应时间<br/>
//     * 5、经过一段时间（时间窗口期，默认是5秒），断路器变为半开状态，会让其中一个请求进行转发。<br/>
//     * &nbsp;&nbsp;5.1、如果成功，断路器会关闭，<br/>
//     * &nbsp;&nbsp;5.2、若失败，继续开启。重复4和5<br/>
//     *
//     * @param id
//     * @return
//     */
//    @HystrixCommand(fallbackMethod = "paymentCircuitBreakerFallback", commandProperties = {
//            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),/* 是否开启断路器*/
//            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),// 请求次数
//            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 时间窗口期
//            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),// 失败率达到多少后跳闸
////            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")// 超时处理
//    })
//    public String paymentCircuitBreaker(Integer id) {
//        if (id < 0) {
//            throw new RuntimeException("******id 不能负数");
//        }
//        //测试异常
////        int age = 10 / 0;
////        int second = 3;
////        try {
////            TimeUnit.SECONDS.sleep(second);
////        } catch (InterruptedException e) {
////            e.printStackTrace();
////        }
//
//
//        String serialNumber = IdUtil.simpleUUID();
//        return Thread.currentThread().getName() + "\t" + "调用成功，流水号: " + serialNumber;
//    }
//
//
//    /**
//     * paymentCircuitBreaker 方法的 fallback，<br/>
//     * 当断路器开启时，主逻辑熔断降级，该 fallback 方法就会替换原 paymentCircuitBreaker 方法，处理请求
//     *
//     * @param id
//     * @return
//     */
//    public String paymentCircuitBreakerFallback(Integer id) {
//        return Thread.currentThread().getName() + "\t" + "id 不能负数或超时或自身错误，请稍后再试，/(ㄒoㄒ)/~~   id: " + id;
//    }

}
